Repository navigation
fix(security): allowlist iframe attributes and source protocols - #21
Merged
Merged
Conversation
Block attributes are controlled by any user able to edit posts, including contributors without unfiltered_html. Custom iframe attributes were only filtered by a denylist, so event handlers (onload) or srcdoc could be stored and executed on the front end and in the editor. - Render only allowlisted attribute names (allow, allowfullscreen, allowpaymentrequest, id, referrerpolicy, sandbox, aria-*, data-*) with a strict name pattern, in PHP and JS. - Restrict the iframe source to http/https in PHP and in the editor. - Parse pasted iframe code in an inert DOMParser document. - Keep the deprecated save output unfiltered to preserve block validation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ft8SsWmmRXSa4kvxVHVdn
- Bump wp-coding-standards/wpcs to 3.4.1: 3.3.0 is blocked by Composer because of security advisory PKSA-mh9b-91zm-m1gy (< 3.4.1). - Bump config.platform.php to 8.3.36: roave/security-advisories now conflicts with PHP 8.3 < 8.3.36. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011ft8SsWmmRXSa4kvxVHVdn
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Block attributes are controlled by any user able to edit posts, including contributors (no
unfiltered_html). The custom iframe attributes were only filtered by a denylist, which allowed stored XSS:includes/BlockRenderer.php): any key/value pair iniframeAttributeswas rendered.onload,srcdoc, or a crafted key such asx onload=alert(1) y(esc_attr()does not escape spaces or=) were output as-is. WordPress'filter_block_kses_value()does not strip these plain strings.src/blockparty-iframe/edit.js/utils.js):srcdocwas passed through to React, andisURL()acceptedjavascript:URLs. Both executed in the wp-admin origin when an admin opened a contributor's post. This could escalate to an administrator account.Changes
allow,allowfullscreen,allowpaymentrequest,id,referrerpolicy,sandbox,aria-*,data-*. Names must also match^[a-z][a-z0-9-]*$.http/https:esc_url( $url, [ 'http', 'https' ] )in PHP, and the newisSafeIframeUrl()in the editor (replacesisURL()).DOMParserdocument, and only allowlisted attributes are kept.save.jskeeps its previous unfiltered output (convertAttributesToRawProps()), so existing posts still pass block validation. That markup is only serialized for comparison, never mounted.CHANGELOG.md: added a Security entry under[Unreleased].Behaviour change
Attributes outside the allowlist (for example
class) are no longer rendered. If a project needs another attribute, add it to both lists (BlockRenderer::ALLOWED_ATTRIBUTESandALLOWED_ATTRIBUTESinutils.js).Test plan
npx wp-scripts lint-js src: no errorsnpm run build: compiled successfullyphp -l includes/BlockRenderer.phponload,srcdoc, a crafted key andclassare dropped;allow,allowfullscreen,data-*andaria-*are kept and escaped; ajavascript:URL renders an empty wrapper.convertAttributesToProps()/isSafeIframeUrl()checked with Node (javascript:anddata:rejected).composer cs(PHPCS): not run locally, becauseroave/security-advisoriesconflicts with the local PHP 8.3.28. Left to CI.{"key":"onload","value":"alert(1)"}and{"key":"srcdoc","value":"<script>alert(1)</script>"}via the code editor.<iframe src="https://…" allowfullscreen allow="…">still works.Generated by Claude Code
Note
Medium Risk
Changes security-sensitive iframe rendering and editor validation; merging is correct hardening but drops non-allowlisted attributes (e.g.
class) and must stay in sync between PHP and JS.Overview
Hardens the Blockparty iframe block against stored XSS from contributor-controlled block attributes by switching from a denylist to a shared allowlist in
BlockRenderer.phpandutils.js(allow, sandbox-related attrs,id,referrerpolicy, plusaria-*/data-*with strict name validation). Event handlers,srcdoc, and malformed attribute names are no longer emitted on the front end or in the editor preview.Iframe
srcis now limited to http/https viaesc_url()with allowed protocols in PHP and newisSafeIframeUrl()in the editor (replacingisURL()). Pasted iframe HTML is parsed withDOMParserinstead of injecting into the live DOM, and only allowlisted attributes are kept.Deprecated
save.jsstill serializes legacy markup throughconvertAttributesToRawProps()so older posts validate; live rendering uses the filteredconvertAttributesToProps().CHANGELOG.mddocuments the security fixes;composer.jsonbumps the PHP platform pin and WPCS.Reviewed by Cursor Bugbot for commit ce015a3. Bugbot is set up for automated code reviews on this repo. Configure here.